using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Xml;
using T.FAS.Runtime.Base.Entity;

namespace T.FAS.Runtime.DataAccess.Common
{
    public interface ICompare
    {
        /// <summary>
        /// 相等性比较
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        bool EqualCompare(object a, object b);
        /// <summary>
        /// 大小比较，如果左值大于右值 返回true，如果右值大于左值 返回false
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        bool QuantitativeCompare(object left, object right);
    }

    public interface IToString
    {
        string TypeToString(object instance);
    }

    public interface IGetCSharpType
    {
        Type GetCSharpType();
    }

    public interface IValidAndConvertToObject
    {
        object ValidAndConvertToObject(object inputVal, bool isAllowNow);
    }

    public class DataTypeToolFactory
    {
        private static Assembly Assembly;
        private static Dictionary<string, AbstractDataTypeTool> Cache = new Dictionary<string, AbstractDataTypeTool>();
        private static object lockObj = new object();
        private static HashSet<Type> s_supportedCSharpTypes = new HashSet<Type>
        {
            typeof(bool),
            typeof(byte[]),
            typeof(int),
            typeof(long),
            typeof(decimal),
            typeof(DateTime),
            typeof(TimeSpan),
            typeof(string),
        };
        static DataTypeToolFactory()
        {
            Assembly = typeof(DataTypeToolFactory).Assembly;
        }

        private static object GetObj(DataType dataType)
        {
            var key = $"{dataType}Tool";
            if (Cache.ContainsKey(key))
                return Cache[key];
            else
            {
                lock (lockObj)
                {
                    if (Cache.ContainsKey(key))
                        return Cache[key];
                    else
                    {
                        Type target = Assembly.GetTypes().Where(t => t.Name == key).FirstOrDefault();
                        if (target != null)
                        {
                            var obj = Activator.CreateInstance(target);
                            var toolObj = (obj as AbstractDataTypeTool);
                            if (toolObj == null)
                                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeToolFactory_GetObj, key));
                            toolObj.DataType = dataType;
                            Cache[key] = toolObj;
                            return obj;
                        }
                        return null;
                    }
                }
            }
        }

        public static ICompare GetCompare(DataType dataType)
        {
            var obj = GetObj(dataType);
            if (obj != null)
                return (ICompare)obj;
            else
                return null;
        }

        public static IGetCSharpType GetTypeMapping(DataType dataType)
        {
            var obj = GetObj(dataType);
            if (obj != null)
                return (IGetCSharpType)obj;
            else
                return null;
        }

        public static IToString GetToString(DataType dataType)
        {
            var obj = GetObj(dataType);
            if (obj != null)
                return (IToString)obj;
            else
                return null;
        }

        public static HashSet<Type> GetSupportedCSharpTypes()
        {
            return s_supportedCSharpTypes;
        }

        public static IValidAndConvertToObject ValidAndConvertToObject(DataType dataType)
        {
            var obj = GetObj(dataType);
            if (obj != null)
                return (IValidAndConvertToObject)obj;
            else
                return null;
        }
    }

    public abstract class AbstractDataTypeTool : ICompare, IGetCSharpType, IToString, IValidAndConvertToObject
    {
        /// <summary>
        /// 默认使用固定的语言文化设置 InvariantCulture
        /// </summary>
        //public static CultureInfo Culture_Const = new CultureInfo("en-US");
        public static CultureInfo Culture_Const = CultureInfo.InvariantCulture;
        public static NumberStyles NumberStyle_Default = NumberStyles.Number;

        /// <summary>
        /// 特殊类型的待比较对象转换后再进行比较
        /// todo:做成接收用户自定义注册比较时可扩展的类型转换方法
        /// </summary>
        private static readonly Dictionary<Type, Func<object, object>> s_specialTypeCast = new Dictionary<Type, Func<object, object>>
        {
            {typeof(JValue), (obj) => {
                try
                {
                    if(obj == null) return null;
                    var tmp = (JValue)obj;
                    return tmp.Value;
                }
                catch (Exception e)
                {
                    throw new FasException(DataAccessErrorCode.DataType.TypeCastError,
string.Format(CommonStringClassCommon.AbstractDataTypeTool_PreprocInputFail,obj.GetType(),obj,e.Message));
                }
            }},
            {typeof(JObject), (obj) => {
                try
                {
                    if(obj == null) return null;
                    var tmp = (JObject)obj;
                    var dict = tmp as IDictionary<string, JToken>;
                    //特殊处理时间戳类型的Json结构，同时包含Data,Format的Json对象默认为TimeStamp对象
                    if(dict.Keys.Contains("Data") && dict.Keys.Contains("Format"))
                    {
                        var val = tmp.GetValue("Data") as JValue;
                        return val?.Value;
                    }
                    var str = tmp.ToString();
                    if(string.Equals(str, "{}"))
                        return null;
                    return str;
                }
                catch (Exception e)
                {
                    throw new FasException(DataAccessErrorCode.DataType.TypeCastError,
string.Format(CommonStringClassCommon.AbstractDataTypeTool_PreprocInputFail,obj.GetType(),obj,e.Message));
                }
            }},
            {typeof(DBNull), (obj) => {
                return null;
            }},
        };

        public DataType DataType { get; set; }

        public abstract Type GetCSharpType();

        /// <summary>
        /// 默认比较方法
        /// </summary>
        /// <param name="a"></param>
        /// <param name="c"></param>
        /// <returns></returns>
        public virtual bool EqualCompare(object a, object b)
        {
            return string.Equals(a?.ToString(), b?.ToString());
        }

        public abstract bool QuantitativeCompare(object left, object right);

        public virtual string TypeToString(object instance)
        {
            return instance?.ToString();
        }

        /// <summary>
        /// 对特殊类型的待比较参数进行特殊处理
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object ProcessSpecialObject(object obj)
        {
            if (obj == null) return null;
            var type = obj.GetType();
            if (s_specialTypeCast.ContainsKey(type))
            {
                return s_specialTypeCast[type](obj);
            }
            return obj;
        }

        #region Common Funcs
        protected DateTime? GetDateTime(object a)
        {
            if (a is DateTime dateTime)
                return dateTime;
            else
            {
                var stringA = a?.ToString();
                if (!string.IsNullOrEmpty(stringA))
                {
                    try
                    {
                        return Convert.ToDateTime(stringA);
                    }
                    catch
                    {
                        throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.AbstractDataTypeTool_GetDateTime, a));
                    }
                }
            }
            return null;
        }

        protected bool CompareDateTime(DateTime? time1, DateTime? time2, DateTimeType dateType)
        {
            if (time1 != null && time2 != null)
            {
                var timeStr1 = time1.Value.ToString("yyyyMMddHHmmssfff");
                var timeStr2 = time2.Value.ToString("yyyyMMddHHmmssfff");
                switch (dateType)
                {
                    case DateTimeType.DateTime:
                        return timeStr1.Substring(0, 14) == timeStr2.Substring(0, 14);
                    case DateTimeType.Timestamp:
                        return timeStr1 == timeStr2;
                    case DateTimeType.Date:
                        return timeStr1.Substring(0, 8) == timeStr2.Substring(0, 8);
                    case DateTimeType.Time:
                        return timeStr1.Substring(8, 6) == timeStr2.Substring(8, 6);
                    default:
                        return false;
                }
            }
            else
            {
                if (time1 == null && time2 == null)
                {
                    return true;
                }
                return false;
            }
        }

        protected bool QuantitativeCompareDateTime(DateTime time1, DateTime time2, DateTimeType dateType)
        {
            switch (dateType)
            {
                case DateTimeType.DateTime:
                case DateTimeType.Timestamp:
                case DateTimeType.Date:
                case DateTimeType.Time:
                default:
                    return time1 > time2;
            }
        }

        public abstract object ValidAndConvertToObject(object inputVal, bool isAllowNow);


        #endregion
    }

    public class BinaryTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            if (!(a is byte[] && b is byte[]))
            {
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.BinaryTool_EqualCompare, DataType, a, b, a?.GetType(), b?.GetType()));
            }
            var ba = (byte[])a;
            var bb = (byte[])b;
            bool lenFlag = ba.Length == bb.Length;
            if (lenFlag)
            {
                for (int i = 0; i < ba.Length; i++)
                {
                    if (ba[i] != bb[i])
                        return false;
                }
            }
            else
            {
                return false;
            }
            return true;
        }

        public override Type GetCSharpType()
        {
            return typeof(byte[]);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            throw new NotImplementedException();
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is byte[] byteVal)
                    return byteVal;
                else
                    //todo:以后或许会用base64传输
                    throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }

    public class BooleanTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            #region 特殊处理Boolean类型

            #endregion
            //bool类型数据库存储的是bit(1)，暂时使用默认比较
            return base.EqualCompare(a, b);
        }

        public override Type GetCSharpType()
        {
            //boolean值可能存在问题，数据库里存储的是0 1，C# boolean为true false，暂时用string处理
            return typeof(bool);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            throw new NotImplementedException();
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is bool boolVal)
                    return boolVal;
                else if (inputVal is int intVal)
                {
                    if (intVal == 0)
                        return false;
                    else if (intVal == 1)
                        return true;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (bool.TryParse(stringVal, out bool boolResult))
                    {
                        return boolResult;
                    }
                    else
                    {
                        if (stringVal == "0")
                            return false;
                        else if (stringVal == "1")
                            return true;
                    }
                }

                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class IntTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            if (a == null && b == null)
            {
                return true;
            }
            else
            {
                if (a == null || b == null)
                {
                    return false;
                }
            }
            if (int.TryParse(string.IsNullOrEmpty(Convert.ToString(a)) ? "0" : a.ToString(), out int intA) &&
                int.TryParse(string.IsNullOrEmpty(Convert.ToString(b)) ? "0" : b.ToString(), out int intB))
            {
                return intA == intB;
            }
            return false;
        }

        public override Type GetCSharpType()
        {
            return typeof(int);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                int leftVal = (int)left;
                int rightVal = (int)right;
                return leftVal > rightVal;
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is int intVal)
                {
                    return intVal;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (int.TryParse(stringVal, out int intVal2))
                    {
                        return intVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class LongTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            if (a == null && b == null)
            {
                return true;
            }
            else
            {
                if (a == null || b == null)
                {
                    return false;
                }
            }
            if (long.TryParse(string.IsNullOrEmpty(Convert.ToString(a)) ? "0" : a.ToString(), out long longA) &&
                long.TryParse(string.IsNullOrEmpty(Convert.ToString(b)) ? "0" : b.ToString(), out long longB))
            {
                return longA == longB;
            }
            return false;
        }

        public override Type GetCSharpType()
        {
            return typeof(long);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                long leftVal = (long)left;
                long rightVal = (long)right;
                return leftVal > rightVal;
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is long longVal)
                {
                    return longVal;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (long.TryParse(stringVal, out long longVal2))
                    {
                        return longVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class DecimalTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            if (a == null && b == null)
            {
                return true;
            }
            else
            {
                if (a == null || b == null)
                {
                    return false;
                }
            }
            if (decimal.TryParse(string.IsNullOrEmpty(Convert.ToString(a)) ? "0" : a.ToString(), NumberStyle_Default, Culture_Const, out decimal decimalA) &&
                decimal.TryParse(string.IsNullOrEmpty(Convert.ToString(b)) ? "0" : b.ToString(), NumberStyle_Default, Culture_Const, out decimal decimalB))
            {
                return decimalA == decimalB;
            }
            return false;
        }

        public override Type GetCSharpType()
        {
            //转化就加入了C# decimal的限制，是否考虑使用string
            return typeof(decimal);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                decimal leftVal = (decimal)left;
                decimal rightVal = (decimal)right;
                return leftVal > rightVal;
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is decimal decimalVal)
                {
                    return decimalVal;
                }
                else if (inputVal is double doubleVal)
                {
                    //double类型直接转换为decimal，不再转为string后用decimal.TryParse方法
                    return Convert.ToDecimal(doubleVal);
                }
                else if (inputVal is float floatVal)
                {

                    //float类型直接转换为decimal，不再转为string后用decimal.TryParse方法
                    return Convert.ToDecimal(floatVal);
                }
                else
                {
                    string stringVal = inputVal.ToString();
                    if (decimal.TryParse(stringVal, NumberStyle_Default, Culture_Const, out decimal decimalVal2))
                    {
                        return decimalVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class DateTimeTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            var dateTimeA = GetDateTime(a);
            var dateTimeB = GetDateTime(b);
            return CompareDateTime(dateTimeA, dateTimeB, DateTimeType.DateTime);
        }

        public override Type GetCSharpType()
        {
            //必须使用DateTime转换，否则会存在精度丢失的问题，导致LastModifyTime时间戳校验失败
            return typeof(DateTime);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                DateTime leftVal = (DateTime)left;
                DateTime rightVal = (DateTime)right;
                return QuantitativeCompareDateTime(leftVal, rightVal, DateTimeType.DateTime);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override string TypeToString(object instance)
        {
            if (instance is DateTime dt)
                return dt.ToString("yyyy-MM-dd HH:mm:ss.fff");
            else
                return null;
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is DateTime DateTimeVal)
                {
                    return DateTimeVal;
                }
                else
                {
                    var val = inputVal.ToString();  //兼容Newtonsoft.Json.Linq.JValue类型
                    if (DateTime.TryParse(val, out DateTime DateTimeVal2))
                    {
                        return DateTimeVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class TimestampTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            var timestampA = GetDateTime(a);
            var timestampB = GetDateTime(b);
            return CompareDateTime(timestampA, timestampB, DateTimeType.Timestamp);
        }

        public override Type GetCSharpType()
        {
            return typeof(DateTime);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                DateTime leftVal = (DateTime)left;
                DateTime rightVal = (DateTime)right;
                return QuantitativeCompareDateTime(leftVal, rightVal, DateTimeType.DateTime);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override string TypeToString(object instance)
        {
            if (instance is DateTime dt)
                return dt.ToString("yyyy-MM-dd HH:mm:ss.fff");
            else
                return null;
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is DateTime DateTimeVal)
                {
                    return DateTimeVal;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (DateTime.TryParse(stringVal, out DateTime DateTimeVal2))
                    {
                        return DateTimeVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class DateTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            var dateA = GetDateTime(a);
            var dateB = GetDateTime(b);
            return CompareDateTime(dateA, dateB, DateTimeType.Date);
        }

        public override Type GetCSharpType()
        {
            return typeof(DateTime);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                DateTime leftVal = (DateTime)left;
                DateTime rightVal = (DateTime)right;
                return QuantitativeCompareDateTime(leftVal, rightVal, DateTimeType.DateTime);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override string TypeToString(object instance)
        {
            if (instance is DateTime dt)
                return dt.ToString("yyyy-MM-dd");
            else
                return null;
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is DateTime DateTimeVal)
                {
                    return DateTimeVal;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (DateTime.TryParse(stringVal, out DateTime DateTimeVal2))
                    {
                        return DateTimeVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class TimeTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            var timeA = GetDateTime(a);
            var timeB = GetDateTime(b);
            return CompareDateTime(timeA, timeB, DateTimeType.Time);
        }

        public override Type GetCSharpType()
        {
            return typeof(TimeSpan);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            try
            {
                DateTime leftVal = (DateTime)left;
                DateTime rightVal = (DateTime)right;
                return QuantitativeCompareDateTime(leftVal, rightVal, DateTimeType.DateTime);
            }
            catch (Exception e)
            {
                throw new FasException(DataAccessErrorCode.Error, string.Format(CommonStringClassCommon.DataTypeTool_QuantitativeCompareFail, DataType, left, right, e.Message), e);
            }
        }

        public override string TypeToString(object instance)
        {
            if (instance is TimeSpan ts)
                return ts.ToString("c");
            else
                return null;
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value || string.IsNullOrEmpty(inputVal.ToString()))
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                if (inputVal is TimeSpan TimeVal)
                {
                    return TimeVal;
                }
                else
                {
                    var stringVal = inputVal.ToString();
                    if (DateTime.TryParse(stringVal, out DateTime dt))
                    {
                        return dt.TimeOfDay;
                    }
                    else if (TimeSpan.TryParse(stringVal, out TimeSpan TimeVal2))
                    {
                        return TimeVal2;
                    }
                }
                throw new FasException(DataAccessErrorCode.DataType.TypeCastError, string.Format(CommonStringClassCommon.DataTypeTool_ValidAndConvertToObjecFail, DataType, inputVal, inputVal.GetType()));
            }
        }
    }
    public class StringTool : AbstractDataTypeTool
    {
        public override bool EqualCompare(object a, object b)
        {
            a = ProcessSpecialObject(a);
            b = ProcessSpecialObject(b);
            return string.Equals(a?.ToString(), b?.ToString());
        }

        public override Type GetCSharpType()
        {
            return typeof(string);
        }

        public override bool QuantitativeCompare(object left, object right)
        {
            throw new NotImplementedException();
        }

        public override object ValidAndConvertToObject(object inputVal, bool isAllowNow)
        {
            inputVal = ProcessSpecialObject(inputVal);
            if (inputVal == null || inputVal == DBNull.Value)
            {
                if (isAllowNow)
                    return DBNull.Value;
                else
                    throw new FasException(DataAccessErrorCode.DataType.NullValue, string.Format(CommonStringClassCommon.DataTypeTool_CannotInputNullValue, DataType));
            }
            else
            {
                return inputVal.ToString();
                //throw new FasException(DataAccessErrorCode.DataType.TypeCastError, $"{DataType}校验失败，输入值:{inputVal}，类型:{inputVal.GetType()}");
            }
        }
    }

    /// <summary>
    /// 日期时间类型枚举
    /// </summary>
    public enum DateTimeType
    {
        DateTime,
        Timestamp,
        Date,
        Time
    }
}